﻿using Modbus.Device;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Timer = System.Timers.Timer;

namespace MonitorModule.Services {
    /// <summary>
    /// 双寄存器实现
    /// </summary>
    public class HeartbeatService {
        #region 字段

        private IModbusSerialMaster _modbusMaster;

        private Timer _heartbeatTimer;
        /// <summary>
        /// 从站地址 
        /// </summary>
        private byte _slaveId = 1;
        /// <summary>
        /// 命令寄存器地址（上位机写入复位指令）
        /// </summary>
        private ushort _commandReg = 40001;
        /// <summary>
        /// 状态寄存器地址（从机自增值）
        /// </summary>
        private ushort _statusReg = 40002;
        /// <summary>
        /// 记录上一次自增值
        /// </summary>
        private int _lastStatusValue = -1;
        /// <summary>
        /// 心跳周期(ms)
        /// </summary>
        private const int HeartbeatInterval = 2000;

        #endregion

        /// <summary>
        /// 创建串口,建立RTU主机,初始化心跳定时器
        /// </summary>
        /// <param name="comPort">串口</param>
        public void Start(string comPort) {
            // 创建串口实例
            SerialPort port = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One);
            port.Open();

            // 创建 Modbus RTU 主站
            _modbusMaster = ModbusSerialMaster.CreateRtu(port);

            // 初始化心跳定时器
            _heartbeatTimer = new Timer(HeartbeatInterval);
            _heartbeatTimer.Elapsed += CheckHeartbeat;
            _heartbeatTimer.AutoReset = true;
            _heartbeatTimer.Start();
        }
        /// <summary>
        /// 心跳定时器绑定的方法:检查心跳
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void CheckHeartbeat(object sender, ElapsedEventArgs e) {
            try {
                // 1. 发送复位命令（写0到命令寄存器）
                _modbusMaster.WriteSingleRegister(_slaveId, _commandReg, 0); // 功能码06[9](@ref)

                // 2. 等待200ms让从机复位并开始自增
                await Task.Delay(200);

                // 3. 读取当前自增值
                ushort currentValue = _modbusMaster.ReadHoldingRegisters(_slaveId, _statusReg, 1)[0];

                // 4. 验证自增连续性（首次跳过）
                if (_lastStatusValue != -1) {
                    // 预期：新值 > 旧值（考虑溢出）
                    bool isValid = currentValue > _lastStatusValue ||
                                  (currentValue == 0 && _lastStatusValue == ushort.MaxValue);

                    if (!isValid)
                        throw new Exception($"心跳异常! 前值:{_lastStatusValue} 当前值:{currentValue}");
                }
                _lastStatusValue = currentValue; // 更新记录值
            } catch (Exception ex) {
                // 异常处理：重连或告警
                Reconnect();
                Console.WriteLine($"心跳失败: {ex.Message}");
            }
        }

        private void Reconnect() {
            _modbusMaster.Dispose();
            Thread.Sleep(1000);
            Start("COM3"); // 重新初始化连接
        }
    }
}
